using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace SypConst.Garbage
{
    [Serializable]
    public sealed class SypGarbageConf : ISerializable
    {
        // This is the one instance of this type.
        private static SypGarbageConf theOneObject = new SypGarbageConf();

        // thread-safe locker
        private static readonly object padlock = new object();

        // Here are the instance fields.
        public int SypServerPort = SypGarbage.SYP_DEFAULT_PORT;

        public bool NotificationEnable = true;
        public int SynchronisingIntervalSec = 0;
        public int SynchronisingIntervalMin = SypGarbage.SYP_DEFAULT_SYNCRHONIZING_INTERVAL;
        public int PublishingIntervalSec = 0;
        public int PublishingIntervalMin = SypGarbage.SYP_DEFAULT_PUBLISHING_INTERVAL;

        public string SypDefaultBrowser = SypGarbageConf.findBrowser();
        public int SypCurrentId = 1;
        public bool WindowsAutoStart = true;
        public string Language = SypGarbage.SYP_CULTURE_FRENCH;

       // private SypGarbageConf() {
       // }

        public static void RemoveAutoStart()
        {
            RegistryKey Nkey = Registry.LocalMachine;
            try
            {
                RegistryKey valKey = Nkey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);
                if (valKey != null)
                {
                    valKey.DeleteValue("SypAgent", false);
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                Nkey.Close();
            }
        }


        public static string findBrowser()
        {
            RegistryKey Nkey = Registry.LocalMachine;
            string ret = "";


            RegistryKey valKey = Nkey.OpenSubKey(SypGarbage.FIREFOX_BROWSER_REGPATH);

            if (valKey != null)
                ret = valKey.GetValue("Path").ToString() + "\\firefox.exe";
            else
            {
                valKey = Nkey.OpenSubKey(SypGarbage.CHROME_BROWSER_REGPATH);
                if (valKey != null)
                    ret = valKey.GetValue("Path").ToString() + "\\chrome.exe";
            }

            Nkey.Close();
            return ret;
        }

        public static void SetAutoStart()
        {

            RegistryKey Nkey = Registry.LocalMachine;

            try
            {
                RegistryKey valKey = Nkey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);

                if (valKey != null)
                {
                    valKey.SetValue("SypAgent", System.Reflection.Assembly.GetExecutingAssembly().Location);
                }

                
            }
            catch (Exception)
            {
            }
            finally
            {
                Nkey.Close();
            }
        }


        static SypGarbageConf()
        {
            //CheckFirefoxVersion();
            LoadSettings();
        }

        ~SypGarbageConf()
        {
            SaveSettings();
        }


        public static void SaveSettings()
        {
            FileStream fs = null;

            try
            {
                //BinaryFormatter formatter = new BinaryFormatter();
                fs = new FileStream(SypGarbage.SYP_GENERAL_CONF_FILE, FileMode.Create);
                XmlSerializer formatter = new XmlSerializer(typeof(SypGarbageConf));
                formatter.Serialize(fs, theOneObject);
            }
            catch (SerializationException e)
            {
                Console.WriteLine("Failed to serialize. Reason: " + e.Message);
                throw;
            }
            finally
            {
                if (fs != null)
                    fs.Close();
            }  
        }

        private static void LoadSettings()
        {
            FileStream fs = null;
            bool resetConfig = false;
            if (File.Exists(SypGarbage.SYP_GENERAL_CONF_FILE))
                fs = new FileStream(SypGarbage.SYP_GENERAL_CONF_FILE, FileMode.Open);

            try
            {
                XmlSerializer formatter = new XmlSerializer(typeof(SypGarbageConf));

                if (!File.Exists(SypGarbage.SYP_GENERAL_CONF_FILE))
                {
                    fs = new FileStream(SypGarbage.SYP_GENERAL_CONF_FILE, FileMode.Create);
                    formatter.Serialize(fs, theOneObject);
                }
                else
                {
                    lock (padlock)
                    {
                        fs.Position = 0;
                        theOneObject = (SypGarbageConf)formatter.Deserialize(fs);
                        if (theOneObject.WindowsAutoStart)
                            SetAutoStart();
                        else
                            RemoveAutoStart();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed to serialize. Reason: " + e.Message);
                //if file exists but an exception raises up it means xml file is wrong formatted. File is deleted. 
                if (File.Exists(SypGarbage.SYP_GENERAL_CONF_FILE))
                    resetConfig = true;
            }
            finally
            {
                fs.Close();
                if (resetConfig)
                    File.Delete(SypGarbage.SYP_GENERAL_CONF_FILE);
            }
        }


        private static void CheckFirefoxVersion()
        {
            RegistryKey Nkey = Registry.LocalMachine;

            try
            {
                RegistryKey valKey = Nkey.OpenSubKey("Software\\Mozilla\\Mozilla Firefox");

                if (valKey != null)
                {
                    string FFVersion = valKey.GetValue("CurrentVersion").ToString();
                    string[] FFVersionTab = FFVersion.Split(new char[] { '.' });
                    int FFMainVersion = 0;
                    if (int.TryParse(FFVersionTab[0], out FFMainVersion) && FFMainVersion >= 3)
                    {
                        //If Firefox version >= 3, we need to decrease the path security policy for XSLT processing.
                        if (Directory.Exists(Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData)))
                        {
                            string FirefoxFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + SypGarbage.FIREFOX_PROFILE_PATH;
                            foreach (string FirefoxProfileFolder in Directory.GetDirectories(FirefoxFolder))
                            {
                                if (FirefoxProfileFolder.Contains(SypGarbage.FIREFOX_PROFILE_FOLDER_FILTER))
                                {
                                    if (File.Exists(FirefoxProfileFolder + "\\" + SypGarbage.FIREFOX_CONFIG_FILE))
                                    {
                                        if (!SypGarbage.SearchIntoFile(FirefoxProfileFolder + "\\" + SypGarbage.FIREFOX_CONFIG_FILE, SypGarbage.FIREFOX_SECURITY_POLICY))
                                        {
                                            SypGarbage.ProcessKill("firefox");
                                            StreamWriter FirefoxConfig = new StreamWriter(FirefoxProfileFolder + "\\" + SypGarbage.FIREFOX_CONFIG_FILE, true);
                                            FirefoxConfig.WriteLine(SypGarbage.FIREFOX_SECURITY_POLICY);
                                            FirefoxConfig.Close();
                                            SypGarbage.ProcessLauncher("firefox", "");
                                        }
                                    }

                                }
                            }
                        }
                    }
                }

                
            }
            catch (Exception)
            {
            }
            finally
            {
                Nkey.Close();
            }
        }

        // A method returning a reference to the Singleton.
        public static SypGarbageConf Instance()
        {
            lock (padlock)
            {
                return theOneObject;
            }
        }

        // A method called when serializing a Singleton.
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            // Instead of serializing this object, 
            // serialize a SingletonSerializationHelp instead.
            info.SetType(typeof(SingletonSerializationHelper));
        }

        public int GetCurrentId()
        {
            lock (padlock)
            {
                return SypCurrentId;
            }
        }

        public int GenerateId()
        {
            lock (padlock)
            {
                return SypCurrentId++;
            }
        }

    }


    [Serializable]
    internal sealed class SingletonSerializationHelper : IObjectReference
    {
        // GetRealObject is called after this object is deserialized.
        public Object GetRealObject(StreamingContext context)
        {
            // When deserialiing this object, return a reference to 
            // the Singleton object instead.
            return SypGarbageConf.Instance();
        }
    }

}
